package com.g2.rpc.rpc.codec;

import com.g2.rpc.common.serialize.Serialization;
import com.g2.rpc.remoting.Codec;
import com.g2.rpc.util.ByteUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.apache.log4j.Logger;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

/**
 * 描述:
 * ${DESCRIPTION}
 *
 * @author lingjiu.kong
 * @version 1.0
 * @date 2021-03-09 0:00
 */
public class G2Codec implements Codec {

    private static Logger log = Logger.getLogger("g2rpc");


    private static final byte FIRST = (byte) 0xaa;
    private static final byte SECOND = (byte) 0xbb;

    private static final byte[] PROTOCOL = {FIRST, SECOND};

    private ByteBuf tmpBuf = Unpooled.buffer();

    @Override
    public List<Object> decode(byte[] bytes) throws Exception{
        List<Object> list = new ArrayList<>();

        ByteBuf byteBuf = Unpooled.buffer();

        int readable = tmpBuf.readableBytes();
        if (readable > 0) {
            log.info("上次剩余" + readable + "大小参与合并");
            byteBuf.writeBytes(tmpBuf);
        }
        byteBuf.writeBytes(bytes);


        while (true) {
            if (byteBuf.readableBytes() < 6) {
                tmpBuf = byteBuf;
                return list;
            }
            tmpBuf.clear();
            byte aa = byteBuf.readByte();
            byte bb = byteBuf.readByte();
            while (true) {
                if (aa == FIRST && bb == SECOND) {
                    break;
                } else {
                    if (byteBuf.readableBytes() > 0) {
                        aa = bb;
                        bb = byteBuf.readByte();
                    } else {
                        tmpBuf.writeByte(bb);
                        return list;
                    }
                }
            }

            byte[] bodyLen = new byte[4];
            byteBuf.readBytes(bodyLen);
            int len = ByteUtil.Bytes2Int_BE(bodyLen);
            if (byteBuf.readableBytes() < len) {
                tmpBuf.writeBytes(PROTOCOL);
                tmpBuf.writeBytes(ByteUtil.int2bytes(len));
                tmpBuf.writeBytes(byteBuf);
                return list;
            }

            byte[] msgBuf = new byte[len];
            byteBuf.readBytes(msgBuf);
            list.add(getSerialization().deserialize(msgBuf, getDecodeType()));
        }
    }

    @Override
    public Codec createInstance() {
        G2Codec g2Codec = new G2Codec();
        g2Codec.setDecodeType(this.decodeType);
        g2Codec.setSerialization(this.serialization);
        return g2Codec;
    }

    @Override
    public byte[] encode(Object message) {
        byte[] message1 = (byte[]) message;
        ByteBuf requestBuffer = Unpooled.buffer();
        requestBuffer.writeBytes(PROTOCOL);
        requestBuffer.writeBytes(ByteUtil.int2bytes(message1.length));
        requestBuffer.writeBytes(message1);

        byte[] result = new byte[requestBuffer.readableBytes()];
        requestBuffer.readBytes(result);
        return result;
    }

    Serialization serialization;

    public void setSerialization(Serialization serialization) {
        this.serialization = serialization;
    }

    public Serialization getSerialization() {
        return this.serialization;
    }


    Class decodeType;

    public Class getDecodeType() {
        return decodeType;
    }

    public void setDecodeType(Class decodeType) {
        this.decodeType = decodeType;
    }
}
